#include "CMyApi.h"
#include "CMySpi.h"
#include "DataCollect.h"
#include <string.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <unistd.h>
#include <chrono>

using namespace std;

//定义交易接口读取config实例
rr::RrConfig tradeconfig;


CMyApi::CMyApi()
{
	//以下为不读取配置文件时的默认参数

	m_pszFrontAddr = const_cast<char*>("tcp://192.168.100.66:51205");
	m_pszBrokerId = const_cast<char*>("0001");
	m_pszUserId = const_cast<char*>("19920324");
	m_pszPasswd = const_cast<char*>("test@123");
	m_pszRemark = const_cast<char*>("正在使用默认配置");
	m_pszPublicIP = const_cast<char*>("192.168.100.20");
	m_pszLoginTime = const_cast<char*>("16:39:00");

	//test
	//直连认证yd
	m_pszProInfo = const_cast<char*>("yd");
	m_pszAuthCode = const_cast<char*>("4JY2D7DIC8KDSAPA");
	m_pszAppID = const_cast<char*>("yd");

	//配置文件路径设置与读取
	CfgFilePath = "config.ini";
	tradeconfig.ReadConfig(CfgFilePath);

	//从配置文件读取交易前置地址
	tmp_pszFrontAddr = tradeconfig.ReadString("network", "frontaddr", "");
	m_pszFrontAddr = const_cast<char*>(tmp_pszFrontAddr.data());

	//从配置文件读取brokerid经纪公司编号
	tmp_pszBrokerId = tradeconfig.ReadString("baseinfo", "brokerid", "");
	m_pszBrokerId = const_cast<char*>(tmp_pszBrokerId.data());

	//从配置文件读取登录账户
	tmp_pszUserId = tradeconfig.ReadString("baseinfo", "userid", "");
	m_pszUserId = const_cast<char*>(tmp_pszUserId.data());

	//从配置文件读取登录密码
	tmp_pszPasswd = tradeconfig.ReadString("baseinfo", "password", "");
	m_pszPasswd = const_cast<char*>(tmp_pszPasswd.data());

	//从配置文件读取appid，appid用于进行客户端认证，需要与认证码成对，长度限制为33个字节
	tmp_pszAppID = tradeconfig.ReadString("authinfo", "appid", "");
	m_pszAppID = const_cast<char*>(tmp_pszAppID.data());

	//从配置文件读取客户端认证码
	tmp_pszAuthCode = tradeconfig.ReadString("authinfo", "authcode", "");
	m_pszAuthCode = const_cast<char*>(tmp_pszAuthCode.data());

	//从配置文件读取客户端标识,这一客户端标示由于有11个字节的限制，并不做认证之用，因此可以自由填写，符合长度即可
	tmp_pszProInfo = tradeconfig.ReadString("authsubinfo", "proinfo", "");
	m_pszProInfo = const_cast<char*>(tmp_pszProInfo.data());

	//从配置文件读取登录备注信息
	tmp_pszRemark = tradeconfig.ReadString("authsubinfo", "remark", "");
	m_pszRemark = const_cast<char*>(tmp_pszRemark.data());

	//从配置文件读取自定义客户端级别appid
	tmp_pszSubAppID = tradeconfig.ReadString("authsubinfo", "subappid", "");
	m_pszSubAppID = const_cast<char*>(tmp_pszSubAppID.data());

	//从配置文件读取自定义上报ip地址
	tmp_pszPublicIP = tradeconfig.ReadString("authsubinfo", "subip", "");
	m_pszPublicIP = const_cast<char*>(tmp_pszPublicIP.data());

	//从配置文件读取自定义上报客户端端口
	tmp_pszSubPort = tradeconfig.ReadString("authsubinfo", "subport", "");
	m_pszSubPort = atoi(tmp_pszSubPort.c_str());

	//从配置文件读取自定义上报登录时间
	tmp_pszLoginTime = tradeconfig.ReadString("authsubinfo", "logintime", "");
	m_pszLoginTime = const_cast<char*>(tmp_pszLoginTime.data());
	
	//从配置文件读取看穿式类型，1为直连，2为多对多，3为一对多（一对多模式会尝试进行两次报送）
	tmp_pszsysinfo_type = tradeconfig.ReadString("authsubinfo", "sysinfotype", "");
	//string类型转int类型
	stringstream stream_trans(tmp_pszsysinfo_type);
	stream_trans >> sysinfo_type;


	//读取看穿式模式后，进行中文提示
	switch (sysinfo_type)
	{
	case 1:
		cout << "curr sysinfo type: 1" << endl;
		break;
	case 2:
		cout << "curr sysinfo type: 2" << endl;
		break;
	case 3:
		cout << "curr sysinfo type: 3 submit twice" << endl;
		break;
	default:
		cout << "curr sysinfo error: check config.ini" << endl;
		break;
	}



	m_iRequestId = 0;


}


CMyApi::~CMyApi()
{
}

//自定义接口初始化函数，绑定Spi类，输入前置地址，定义接受数据类型
void CMyApi::Init()
{
	m_pApi = CThostFtdcTraderApi::CreateFtdcTraderApi("");
	m_pSpi = new CMySpi(this);

	m_pApi->RegisterSpi(m_pSpi);
	m_pApi->RegisterFront(m_pszFrontAddr);

	//以下配置模式，是只收取程序登录后的回报信息，与报单测试有关，特别注意
	m_pApi->SubscribePublicTopic(THOST_TERT_QUICK);
	m_pApi->SubscribePrivateTopic(THOST_TERT_QUICK);

	//赋值请求开始时间
	gettimeofday(&starttime, NULL);
	m_pApi->Init();//该行为CThostFtdcTraderApi类对象的初始化，并非CMyApi的初始化，我们定义的是CMyApi的初始化

	//进程主动控制
	serverrt = false;
	unique_lock<mutex> lk(mu);
	cond.wait_for(lk, chrono::seconds(5));
	if(serverrt)
	{
		cout << "lock end for init" << endl;
	}
	else
	{
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
	}



	//m_pApi->Join();
}

void CMyApi::Destroy()
{
	cout << "spi set null" << endl;
	m_pApi->RegisterSpi(NULL);
	cout << "to release" << endl;
	m_pApi->Release();
	cout << "set api null" << endl;
	m_pApi = NULL;
}

//自定义客户端认证函数，为原始客户端认证函数结构体赋值，赋值内容已在构造函数内定义
void CMyApi::RequestAuth()
{
	//cout << "进入认证函数" << endl;
	CThostFtdcReqAuthenticateField reqauth;

	strcpy(reqauth.BrokerID, m_pszBrokerId);
	strcpy(reqauth.UserID, m_pszUserId);
	strcpy(reqauth.UserProductInfo, m_pszProInfo);
	strcpy(reqauth.AuthCode, m_pszAuthCode);
	//新接口尤其注意输入AppID，后台对比AppID与AuthCode的匹配，只输入UserProductInfo无法认证成功
	strcpy(reqauth.AppID, m_pszAppID);

	//赋值请求开始时间
	gettimeofday(&starttime, NULL);
	//调用认证函数
	int iRet = m_pApi->ReqAuthenticate(&reqauth, m_iRequestId++);

	//进程主动控制
	serverrt = false;
	unique_lock<mutex> lk(mu);
	cond.wait_for(lk, chrono::seconds(5));
	if(serverrt)
	{
		cout << "lock end for auth" << endl;
	}
	else
	{
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
	}

}

//自定义登陆函数
void CMyApi::RequestLogin()
{
	CThostFtdcReqUserLoginField reqlogin;

	strcpy(reqlogin.BrokerID, m_pszBrokerId);
	strcpy(reqlogin.UserID, m_pszUserId);
	strcpy(reqlogin.Password, m_pszPasswd);
	strcpy(reqlogin.UserProductInfo, m_pszProInfo);
	strcpy(reqlogin.LoginRemark, m_pszRemark);

	//赋值请求开始时间
	gettimeofday(&starttime, NULL);
	//调用认证函数
	int iRet = m_pApi->ReqUserLogin(&reqlogin, m_iRequestId++);

	//进程主动控制
	serverrt = false;
	unique_lock<mutex> lk(mu);
	cond.wait_for(lk, chrono::seconds(5));
	if(serverrt)
	{
		cout << "lock end for login" << endl;
	}
	else
	{
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
	}
}

void CMyApi::ReqQryDepMD(char *list[], int &count)
{
	instrcount = 0;
	CThostFtdcQryDepthMarketDataField reqDepMD;
	memset(&reqDepMD, 0, sizeof(reqDepMD));

	int iRet = m_pApi->ReqQryDepthMarketData(&reqDepMD, m_iRequestId++);

	//进程主动控制
	serverrt = false;
	unique_lock<mutex> lk(mu);
	cond.wait_for(lk, chrono::seconds(10));
	if(serverrt)
	{
		cout << "lock end for qrydepmd" << endl;
		count = instrcount;
		//复制行情列表给参数变量
		for(int i=0; i<instrcount; i++)
		{
			//合约长度为char [81]
			list[i] = (char*)malloc(81 * sizeof(char));
			strcpy(list[i], instrumentlist[i]);
		}
	}
	else
	{
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
		cout << "connect time out!!!" << endl;
	}
}

//自定义多对多中继模式报送函数
void CMyApi::UserInfoRegister()
{
	CThostFtdcUserSystemInfoField userinfo;

	strcpy(userinfo.BrokerID, m_pszBrokerId);
	strcpy(userinfo.UserID, m_pszUserId);
	strcpy(userinfo.ClientPublicIP, m_pszPublicIP);//手工填写IP地址
	strcpy(userinfo.ClientLoginTime, m_pszLoginTime);//手工填写登录时间
	strcpy(userinfo.ClientAppID, m_pszSubAppID);//手工填写AppID，算是下级appid的标示，与relayappid有所区别
	userinfo.ClientIPPort = m_pszSubPort; //手工填写客户端发起session接口
	CTP_GetSystemInfo(userinfo.ClientSystemInfo, userinfo.ClientSystemInfoLen);//使用信息采集函数，将加密数据传递给参数

	cout << "采集信息字段长度为：" << userinfo.ClientSystemInfoLen << endl;


	int i_userinfo = m_pApi->RegisterUserSystemInfo(&userinfo);
}

//自定义一对多中继模式报送函数
void CMyApi::UserInfoSubmit()
{
	CThostFtdcUserSystemInfoField userinfosub;

	strcpy(userinfosub.BrokerID, m_pszBrokerId);
	strcpy(userinfosub.UserID, m_pszUserId);
	strcpy(userinfosub.ClientPublicIP, m_pszPublicIP);//手工填写IP地址
	strcpy(userinfosub.ClientLoginTime, m_pszLoginTime);//手工填写登录时间
	strcpy(userinfosub.ClientAppID, m_pszSubAppID);//手工填写AppID，算是下级appid的标示，与relayappid有所区别
	userinfosub.ClientIPPort = m_pszSubPort;//手工填写客户端发起session接口
	CTP_GetSystemInfo(userinfosub.ClientSystemInfo, userinfosub.ClientSystemInfoLen);//使用信息采集函数，将加密数据传递给参数

	cout << "采集信息字段长度为：" << userinfosub.ClientSystemInfoLen << endl;

	int i_userinfo_usb = m_pApi->SubmitUserSystemInfo(&userinfosub);

}

